
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>

#include "app_des.h"
#include "mid_md5.h"

#define EPG_PASSWD_LEN  3200
#define USER_LEN        34

static void md5_encypt_163(char **array, int num, char *enc, int flag)
{
    unsigned char digest[16] = {0};
    char buf[48] = {0};
    int i = 0, len = 0;
    mid_MD5_CTX ctx;
    len = 0;
    i = 0;

    mid_MD5Init(&ctx);
    for(i = 0; i < num; i ++)
        mid_MD5Update(&ctx, (unsigned char *)array[i], strlen(array[i]));
    mid_MD5Final(digest, &ctx);
    len = 0;
    if(0 == flag) {
        for(i = 0; i < 12; i ++)
            len += sprintf(buf + len, "%02x", digest[i]);
    }
    else {
        for(i = 0; i < 16; i ++)
            len += sprintf(buf + len, "%02x", digest[i]);
        for(i = 0; i < (int)strlen(buf); i++)
            buf [i] = toupper(buf[i]);
    }
    strcpy(enc, buf);
    return;
}

static void md5_encypt_huawei(char **array, int num, char *enc, int flag)
{
    unsigned char digest[64] = {0};
    char buf[48] = {0};
    int i, len;
    mid_MD5_CTX ctx;

    len = 0;
    i = 0;
    mid_MD5Init(&ctx);
    for(i = 0; i < num; i ++)
        mid_MD5Update(&ctx, (unsigned char *)array[i], strlen(array[i]));
    mid_MD5Update(&ctx, (unsigned char *)"99991231", 8);
    mid_MD5Final(digest, &ctx);
    len = 0;
    if(0 == flag) {
        for(i = 0; i < 16 && len < 8; i ++)
            len += sprintf(buf + len, "%x", digest[i]);
        buf[8] = '\0';
    } else {
        for(i = 0; i < 32 && len < 32; i ++)
            len += sprintf(buf + len, "%x", digest[i]);
        buf[32] = '\0';
        //	for(i=0;i<strlen(buf);i++)  是否需要转化成大写
        //		buf [i] = toupper (buf[i]);
    }
    strcpy(enc, buf);
    return;
}


char * un3des(const char * line, const char * password, const char * type, char * output, int len)
{
    // char lStrText[EPG_PASSWD_LEN] = { 0 };

    char lPassword[USER_LEN] = {0};
    char encyptData[USER_LEN] = {0};
    char *cont = NULL;
    int lCodeLength = 0, lTextLength = 0, i = 0;
    // char lICKey[] = "unknown ICKey00000000000";
    DES_cblock lKey1, lKey2, lKey3;
    DES_key_schedule lKs1, lKs2, lKs3;
    DES_cblock lPlainText[40], lEncryptOut[40];

    cont = (char *)password;

    if(!strncmp(type, "0001", 4)) {
        strcpy(lPassword, cont);
    } else if(!strncmp(type, "0002", 4)) {
        if(32 == strlen(cont)) {
            strncpy(lPassword, cont, 8);  // get the first 8 characters of the md5 digest
        } else {
            md5_encypt_huawei(&cont, 1, encyptData, 2);
            strncpy(lPassword, encyptData, 8);  // get the first 8 characters of the md5 digest
        }
    } else if(!strncmp(type, "0003", 4)) {
        if(32 == strlen(cont)) {
            strncpy(lPassword , cont, 24); // get the first 24 characters of the md5 digest
        } else {
            md5_encypt_163(&cont, 1, encyptData, 2);
            strncpy(lPassword , encyptData, 24); // get the first 24 characters of the md5 digest
        }
    } else {
        strcpy(lPassword, password);
    }

    lCodeLength = 24 - strlen(lPassword);
    if(lCodeLength > 0)
        for(i = 0; i < lCodeLength; ++i)
            strcat(lPassword, "0");

#if 1
        for(i = 0; i < 24; ++i) {
            switch(i / 8) {
                case 0: /* 0 - 7 */
                    lKey1[i % 8] = (unsigned char)lPassword[i];
                    break;
                case 1: /* 8 - 15 */
                    lKey2[i % 8] = (unsigned char)lPassword[i];
                    break;
                case 2: /* 16 - 23 */
                    lKey3[i % 8] = (unsigned char)lPassword[i];
                    break;
                default:
                    break;
            }
        }
#else
        // {{{
        for(i = 0; i < 24; ++i) {
            switch(i / 8) {
                case 0: /* 0 - 7 */
                    lKey1[i % 8] = (unsigned char)lICKey[i];
                    break;
                case 1: /* 8 - 16 */
                    lKey2[i % 8] = (unsigned char)lICKey[i];
                    break;
                case 2: /* 16 - 23 */
                    lKey3[i % 8] = (unsigned char)lICKey[i];
                    break;
                default:
                    break;
            }
        }
        // }}}
#endif

    lTextLength    = strlen(line) / 8 + 1 ;
    /*
    int lTextRemainder = strlen(lStrText) % 8;

    for (i=0;  i<lTextRemainder; i++) {
        for (j=0; j<8; j++) {
        }
    }
    */
    char * p = (char *)lPlainText;
    for (i=0; i<(int)strlen(line); i+=2) {
        char    temp[10];
        strncpy(temp, line + i, 3);
        temp[2] = '\0';
        int c;
        sscanf(temp, "%x", &c);
        *p = (char)c;
        p++;
    }

#if 0
    for(i = 0; i < lTextLength; ++i) {
        for(j = 0; j < 8; ++j)
            lPlainText[i][j] = 0;
    }
    for(i = 0; i < lTextLength; ++i) {
        for(j = 0; j < 8; ++j) {
            if(i == lTextLength - 1 && j >= lTextRemainder)
                lPlainText[i][j] = 0x08 - lTextRemainder; /* Padding bytes must be the multiple of 8 */
            else
                lPlainText[i][j] = lStrText[i * 8 + j];
        }
    }
#endif

    mid_DES_set_key_unchecked(&lKey1, &lKs1);
    mid_DES_set_key_unchecked(&lKey2, &lKs2);
    mid_DES_set_key_unchecked(&lKey3, &lKs3);

    for(i = 0; i < lTextLength; ++i) {
        mid_DES_ecb3_encrypt(&lPlainText[i], &lEncryptOut[i], &lKs1, &lKs2, &lKs3, DES_DECRYPT);
    }

    memset(output, 0, len);
    for (i=0; i<lTextLength; i++) {
        int j;
        for (j=0; j < 8; j++) {
            output[i * 8 + j] = lEncryptOut[i][j];
        }
    }
    int ll = strlen(line) / 2;
    int l = output[ll - 1];
    output[ll - l] = '\0';
    return output;
    /*
    lLength = 0;
    for(i = 0; i < lTextLength; i++) {
        for(j = 0; j < 8; ++j)
            lLength += sprintf(nOutStr + lLength, "%02X", lEncryptOut[i][j]);
    }
    return nOutStr;
    */
}

char *CTCGetAuthInfo(char* nOutStr, int nSize, const char * token, const char * lNetAdr, const char * lMacAdr, const char * lNtvID, const char * lStbID, const char * lStrEncrypType, const char * password)
{
    if(!nOutStr || !nSize || !lNetAdr || !lMacAdr || !lNtvID || !lStbID)
        return NULL;

    // printf("%s\n%s\n%s\n%s\n%s\n%s\n", lNetAdr, lMacAdr, lNtvID, lStbID, lStrEncrypType, password);

    // 1. concat the authentication string
    int  lLength = 0;
    char lStrText[EPG_PASSWD_LEN] = { 0 };
    char lRandom[9] = { '\n' };

    srand(time(NULL));
    sprintf(lRandom, "%u", rand() % 100000000);

    lLength = snprintf(lStrText, EPG_PASSWD_LEN, "%s$%s$%s$%s$%s$%s$$CTC", lRandom, token, lNtvID, lStbID, lNetAdr, lMacAdr);
    // printf("\n%s\n", lStrText);
    if(lLength > nSize) {
        return NULL;
    }

    char lPassword[USER_LEN] = {0};
    char encyptData[USER_LEN] = {0};
    char *cont = NULL;
    int lCodeLength = 0, lTextLength = 0, lTextRemainder = 0, lSegregation = 1, i = 0, j = 0;
    char lICKey[] = "unknown ICKey00000000000";
    DES_cblock lKey1, lKey2, lKey3;
    DES_key_schedule lKs1, lKs2, lKs3;
    DES_cblock lPlainText[40], lEncryptOut[40];

    cont = (char *)password;

    if(lStrEncrypType) {
        if(!strncmp(lStrEncrypType, "0001", 4)) {
            strcpy(lPassword, cont);
        }
        else if(!strncmp(lStrEncrypType, "0002", 4)) {
            if(32 == strlen(cont)) {
                strncpy(lPassword, cont, 8);  // get the first 8 characters of the md5 digest
            } else {
                md5_encypt_huawei(&cont, 1, encyptData, 2);
                strncpy(lPassword, encyptData, 8);  // get the first 8 characters of the md5 digest
            }
        }
        else if(!strncmp(lStrEncrypType, "0003", 4)) {
            if(32 == strlen(cont)) {
                strncpy(lPassword , cont, 24); // get the first 24 characters of the md5 digest
            } else {
                md5_encypt_163(&cont, 1, encyptData, 2);
                strncpy(lPassword , encyptData, 24); // get the first 24 characters of the md5 digest
            }
        }
        else {
            strcpy(lPassword, password);
        }
    }
    else {
        strcpy(lPassword, password);
    }

    lCodeLength = 24 - strlen(lPassword);
    if(lCodeLength > 0)
        for(i = 0; i < lCodeLength; ++i)
            strcat(lPassword, "0");

    if(lSegregation) {
        for(i = 0; i < 24; ++i) {
            switch(i / 8) {
                case 0: /* 0 - 7 */
                    lKey1[i % 8] = (unsigned char)lPassword[i];
                    break;
                case 1: /* 8 - 15 */
                    lKey2[i % 8] = (unsigned char)lPassword[i];
                    break;
                case 2: /* 16 - 23 */
                    lKey3[i % 8] = (unsigned char)lPassword[i];
                    break;
                default:
                    break;
            }
        }
    }
    else {
        for(i = 0; i < 24; ++i) {
            switch(i / 8) {
                case 0: /* 0 - 7 */
                    lKey1[i % 8] = (unsigned char)lICKey[i];
                    break;
                case 1: /* 8 - 16 */
                    lKey2[i % 8] = (unsigned char)lICKey[i];
                    break;
                case 2: /* 16 - 23 */
                    lKey3[i % 8] = (unsigned char)lICKey[i];
                    break;
                default:
                    break;
            }
        }
    }

    lTextLength    = strlen(lStrText) / 8 + 1 ;
    lTextRemainder = strlen(lStrText) % 8;
    for(i = 0; i < lTextLength; ++i) {
        for(j = 0; j < 8; ++j)
            lPlainText[i][j] = 0;
    }
    for(i = 0; i < lTextLength; ++i) {
        for(j = 0; j < 8; ++j) {
            if(i == lTextLength - 1 && j >= lTextRemainder)
                lPlainText[i][j] = 0x08 - lTextRemainder; /* Padding bytes must be the multiple of 8 */
            else
                lPlainText[i][j] = lStrText[i * 8 + j];
        }
    }

    mid_DES_set_key_unchecked(&lKey1, &lKs1);
    mid_DES_set_key_unchecked(&lKey2, &lKs2);
    mid_DES_set_key_unchecked(&lKey3, &lKs3);

    for(i = 0; i < lTextLength; ++i)
        mid_DES_ecb3_encrypt(&lPlainText[i], &lEncryptOut[i], &lKs1, &lKs2, &lKs3, DES_ENCRYPT);

    lLength = 0;
    for(i = 0; i < lTextLength; i++) {
        for(j = 0; j < 8; ++j)
            lLength += sprintf(nOutStr + lLength, "%02X", lEncryptOut[i][j]);
    }

    return nOutStr;
}


